//===--- InvertibleProtocols.h - invertible protocol meta ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This header declares various types for invertible protocols, such as
// Copyable.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_ABI_INVERTIBLEPROTOCOLS_H
#define SWIFT_ABI_INVERTIBLEPROTOCOLS_H

#include <cstdint>
#include <initializer_list>
#include <iterator>

namespace swift {

/// Describes an "invertible" protocol, such as Copyable, which is assumed to
/// hold for all types unless explicitly indicated otherwise.
enum class InvertibleProtocolKind : uint8_t {
#define INVERTIBLE_PROTOCOL(Name, Bit) Name = Bit,
#include "swift/ABI/InvertibleProtocols.def"
};

/// A set of invertible protocols, whose bits correspond to the cases of
/// InvertibleProtocolKind.
class InvertibleProtocolSet {
  using StorageType = uint16_t;
  
  /// The stored bits.
  StorageType bits;

  /// Retrieve the mask for this bit.
  static StorageType getMask(InvertibleProtocolKind kind) {
    return 1 << static_cast<uint8_t>(kind);
  }
  
public:
  explicit constexpr InvertibleProtocolSet(StorageType bits) : bits(bits) {}
  constexpr InvertibleProtocolSet() : bits(0) {}

  InvertibleProtocolSet(
      std::initializer_list<InvertibleProtocolKind> elements
  ) : bits(0) {
    for (auto element : elements)
      insert(element);
  }

  /// Retrieve the raw bits that describe this set.
  StorageType rawBits() const { return bits; }

  /// Whether the set contains no protocols.
  bool empty() const { return bits == 0; }

  /// Check whether the set contains the specific invertible protocol.
  bool contains(InvertibleProtocolKind kind) const {
    return bits & getMask(kind);
  }

  /// Insert the invertible protocol into the set.
  void insert(InvertibleProtocolKind kind) {
    bits = bits | getMask(kind);
  }

  /// Insert all of the invertible protocols from the other set into this
  /// one.
  void insertAll(InvertibleProtocolSet other) {
    bits |= other.bits;
  }

  /// Remove the given invertible protocol from the set.
  void remove(InvertibleProtocolKind kind) {
    uint16_t mask = getMask(kind);
    bits = bits & ~mask;
  }

  /// Clear out all of the protocols from the set.
  void clear() { bits = 0; }

#define INVERTIBLE_PROTOCOL(Name, Bit)             \
  bool contains##Name() const {                      \
    return contains(InvertibleProtocolKind::Name); \
  }
#include "swift/ABI/InvertibleProtocols.def"

  /// Produce a invertible protocol set containing all known invertible
  /// protocols.
  static InvertibleProtocolSet allKnown() {
    InvertibleProtocolSet result;
#define INVERTIBLE_PROTOCOL(Name, Bit)           \
    result.insert(InvertibleProtocolKind::Name);
#include "swift/ABI/InvertibleProtocols.def"
    return result;
  }

  /// Determine whether this protocol set contains any unknown protocols.
  ///
  /// This can occur when an older Swift runtime is working with metadata
  /// or mangled names generated by a newer compiler that has introduced
  /// another kind of invertible protocol. The Swift runtime will need to
  /// step lightly around protocol sets with unknown protocols.
  bool hasUnknownProtocols() const {
    return !(*this - allKnown()).empty();    
  }
  
  class iterator {
    /// The bits remaining in the set, which will be 0 when we have hit the
    /// end.
    unsigned bitsRemaining;

    /// The current bit index
    unsigned currentBitIndex;

    /// Advance to the next set bit.
    void advance() {
      // Already at the end.
      if (bitsRemaining == 0)
        return;

      do {
        ++currentBitIndex;
        unsigned mask = 1 << currentBitIndex;
        if ((bitsRemaining & mask) != 0)
          break;
      } while (true);
    }

    /// Clear out the current bit, then advance.
    void clearAndAdvance() {
      // Clear the current bit.
      unsigned mask = 1 << currentBitIndex;
      bitsRemaining = bitsRemaining & ~mask;

      // Advance to the next set bit, or stop if we're done.
      advance();
    }

  public:
    using difference_type = int;
    using value_type = InvertibleProtocolKind;
    using pointer = void;
    using reference = value_type;
    using iterator_category = std::input_iterator_tag;

    iterator() : bitsRemaining(0), currentBitIndex(0) { }
    iterator(unsigned bitsRemaining)
        : bitsRemaining(bitsRemaining), currentBitIndex(0)
    {
      if ((bitsRemaining & 0x01) == 0)
        advance();
    }

    iterator &operator++() {
      clearAndAdvance();
      return *this;
    }

    iterator operator++(int) {
      iterator tmp = *this;
      ++(*this);
      return tmp;
    }

    InvertibleProtocolKind operator*() const {
      return static_cast<InvertibleProtocolKind>(currentBitIndex);
    }

    friend bool operator ==(iterator lhs, iterator rhs) {
      if (lhs.bitsRemaining != rhs.bitsRemaining)
        return false;

      if (lhs.bitsRemaining == 0)
        return true;

      return lhs.currentBitIndex == rhs.currentBitIndex;
    }

    friend bool operator !=(iterator lhs, iterator rhs) {
      return !(lhs == rhs);
    }
  };

  iterator begin() const { return iterator(rawBits()); }
  iterator end() const { return iterator(0); }

  friend bool operator==(
      InvertibleProtocolSet lhs, InvertibleProtocolSet rhs) {
    return lhs.bits == rhs.bits;
  }

  friend bool operator!=(
      InvertibleProtocolSet lhs, InvertibleProtocolSet rhs) {
    return lhs.bits != rhs.bits;
  }

  friend InvertibleProtocolSet operator-(
      InvertibleProtocolSet lhs, InvertibleProtocolSet rhs) {
    return InvertibleProtocolSet(lhs.bits & ~rhs.bits);
  }

  InvertibleProtocolSet &operator-=(InvertibleProtocolSet rhs) {
    bits = bits & ~rhs.bits;
    return *this;
  }

  friend InvertibleProtocolSet operator|(
      InvertibleProtocolSet lhs, InvertibleProtocolSet rhs) {
    return InvertibleProtocolSet(lhs.bits | rhs.bits);
  }

  InvertibleProtocolSet &operator|=(InvertibleProtocolSet rhs) {
    bits |= rhs.bits;
    return *this;
  }
};

/// Retrieve the name for the given invertible protocol.
static inline const char *
getInvertibleProtocolKindName(InvertibleProtocolKind kind) {
  switch (kind) {
#define INVERTIBLE_PROTOCOL(Name, Bit)             \
  case InvertibleProtocolKind::Name: return #Name;
#include "swift/ABI/InvertibleProtocols.def"
  }

  return "<unknown invertible protocol kind>";
}

} // end namespace swift
#endif // SWIFT_ABI_INVERTIBLEPROTOCOLS_H
